<?php


namespace app\api\service;


use app\api\model\User;
use app\lib\enum\ScopeEnum;
use app\lib\exception\TokenException;
use app\lib\exception\WeChatException;
use think\Exception;

class UserToken extends BaseToken
{
    protected $code; // 小程序传递的code码
    protected $wxAppID;
    protected $wxAppSecret;
    protected $wxLoginUrl;

    // 构造函数 拼写完整wxLoginUrl
    function __construct($code)
    {
        // 赋值
        $this->code = $code;
        $this->wxAppID = config('wx.app_id');
        $this->wxAppSecret = config('wx.app_secret');
        $this->wxLoginUrl = sprintf(
            config('wx.login_url'),
            $this->wxAppID, $this->wxAppSecret, $this->code);
    }

    public function get()
    {
        // 调用封装的HTTP请求方法
        $result = curl_get($this->wxLoginUrl);
        // 将字符串转换成数组
        $wxResult = json_decode($result, true);
        if (empty($wxResult)) {
            throw new Exception('获取session_key及openID异常，微信内部错误');
        } else {
            // 判断errcode是否存在(接口调用出错，微信会返回errcode码)
            $loginFail = array_key_exists('errcode', $wxResult);
            if ($loginFail) {
                // 调用失败
                $this->processLoginError($wxResult);
            } else {
                // 调用成功
                return $this->grantToken($wxResult);
            }
        }
    }

    // 封装生成令牌函数
    private function grantToken($wxResult)
    {
        // 获取openid
        $openid = $wxResult['openid'];

        // 查询数据库是否存在openid
        $user = User::getByOpenID($openid);
        if ($user) {
            // 用户存在，通过查询模型得到id
            $uid = $user->id;
        } else {
            // 用户不存在，先创建用户在查询
            /*$uid = $this->newUser($openid);*/
        }
        // 生成令牌，缓存数据(key: 令牌; value: wxResult,uid,scope)，写入缓存
        $cacheValue = $this->prepareCacheValue($wxResult, $uid);
        // 将令牌返回到客户端
        $token = $this->saveToCache($cacheValue);

        return $token;
    }

    // 准备缓存数据中的value
    private function prepareCacheValue($wxResult, $uid)
    {
        $cacheValue = $wxResult;
        // 将$uid存入缓存的uid字段
        $cacheValue['uid'] = $uid;
        // 当前用户权限赋值16
        $cacheValue['scope'] = ScopeEnum::User;
        return $cacheValue;
    }

    //写入缓存
    private function saveToCache($cacheValue)
    {
        // 声明key
        $key = self::generateToken();
        $value = json_encode($cacheValue);
        // 缓存过期时间
        $expire_in = config('setting.token_expire_in');

        // 缓存
        $request = cache($key, $value, $expire_in);

        // 容错
        if (!$request) {
            throw new TokenException([
                'msg' => '服务器缓存异常',
                'errorCode' => 1005
            ]);
        }

        // 返回令牌
        return $key;
    }

    // 创建用户方法
    /*private function newUser($openid)
    {
        $user = User::create(['open_id' => $openid]);
        // 返回user的id字段
        return $user->id;
    }*/

    // 封装异常处理函数返回异常到客户端
    private function processLoginError($wxResult)
    {
        throw new WeChatException([
            'msg' => $wxResult['errmsg'],
            'errorCode' => $wxResult['errcode']
        ]);
    }
}